﻿using System;
using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.Xml.Dom;
using sharpxbot.Core.Configuration;

namespace sharpxbot.Core.Connection
{
    /// <summary>
    /// Adapts XmppClientConnection to IConnection interface
    /// </summary>
    public class ConnectionAdapter : IConnection
    {
        public ConnectionAdapter(IConfiguration configuration)
        {
            if (configuration == null)
                throw new NullReferenceException("Illegal null-regerence configuration ctor argument");

            this.conn = new XmppClientConnection();
            this.configuration = configuration;
        }

        #region IConnection Members

        public XmppConnectionState State { get { return conn.XmppConnectionState; } }

        public XmppConnectionStateHandler ConnectionStateChanged { get; set; }

        public ObjectHandler OnLogin { get; set; }

        public ObjectHandler OnClose { get; set; }

        public ObjectHandler OnSessionStarted { get; set; }

        public PresenceHandler OnPresence { get; set; }

        public MessageHandler OnMessage { get; set; }

        public SocketDataHandler OnSocketWrite { get; set; }

        public SocketDataHandler OnSocketRead { get; set; }

        /// <summary>
        /// Opens connection
        /// </summary>
        public void Open()
        {
            if (State == XmppConnectionState.Disconnected)
            {
                InitConnection(conn);
                conn.Open();
            }
        }

        public void Close()
        {
            conn.Close();
        }

        public void Send(Element msg)
        {
            conn.Send(msg);
        }

        public void Send(string xml)
        {
            conn.Send(xml);
        }

        #endregion

        #region Private methods

        private void InitConnection(XmppClientConnection conn)
        {
            conn.AutoAgents = false;
            conn.AutoPresence = false;
            conn.AutoRoster = false;
            conn.AutoResolveConnectServer = true;

            conn.Username = configuration.UserName;
            conn.Password = configuration.Password;
            conn.Server = configuration.Server;
            conn.UseStartTLS = true;
            conn.UseSSL = false;

            if (!eventsInitialized) // we don't need to add duplicate subsciptions on network failure and reconnect
            {
                conn.OnXmppConnectionStateChanged += conn_OnXmppConnectionStateChanged;
                conn.OnLogin += conn_OnLogin;
                conn.OnPresence += conn_OnPresence;
                conn.OnMessage += conn_OnMessage;
                conn.OnClose += conn_OnClose;
                conn.OnWriteSocketData += conn_OnSocketWrite;
                conn.OnReadSocketData += conn_OnSocketRead;

                eventsInitialized = true;
            }
        }

        void conn_OnClose(object sender)
        {
            if (OnClose != null)
            {
                OnClose(this);
            }
        }

        void conn_OnXmppConnectionStateChanged(object sender, XmppConnectionState state)
        {
            if (ConnectionStateChanged != null)
            {
                ConnectionStateChanged(sender, state);
            }
        }

        void conn_OnLogin(object sender)
        {
            if (OnLogin != null)
            {
                //send IConnection as argument
                OnLogin(this);
            }

            conn.SendMyPresence();
        }

        void conn_OnPresence(object sender, Presence pres)
        {
            if (OnPresence != null)
            {
                OnPresence(sender, pres);
            }
        }

        void conn_OnMessage(object sender, Message msg)
        {
            if (OnMessage != null)
            {
                OnMessage(sender, msg);
            }
        }

        void conn_OnSocketWrite(object sender, byte[] data, int count)
        {
            if (OnSocketWrite != null)
            {
                OnSocketWrite(count);
            }
        }

        void conn_OnSocketRead(object sender, byte[] data, int count)
        {
            if (OnSocketRead != null)
            {
                OnSocketRead(count);
            }
        }


        #endregion

        #region Private fields

        private XmppClientConnection conn;
        private IConfiguration configuration;

        private bool eventsInitialized;


        #endregion
    }
}
